package com.atguigu.tingshu.comment.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.atguigu.tingshu.album.client.AlbumClientFeign;
import com.atguigu.tingshu.comment.service.CommentService;
import com.atguigu.tingshu.common.execption.GuiguException;
import com.atguigu.tingshu.common.result.Result;
import com.atguigu.tingshu.common.util.AuthContextHolder;
import com.atguigu.tingshu.model.comment.Comment;
import com.atguigu.tingshu.model.user.UserInfo;
import com.atguigu.tingshu.user.client.UserClientFeign;
import com.atguigu.tingshu.vo.comment.CommentVo;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.tencentcloudapi.common.AbstractModel;
import com.tencentcloudapi.common.Credential;
import com.tencentcloudapi.common.profile.ClientProfile;
import com.tencentcloudapi.common.profile.HttpProfile;
import com.tencentcloudapi.tms.v20201229.TmsClient;
import com.tencentcloudapi.tms.v20201229.models.TextModerationRequest;
import com.tencentcloudapi.tms.v20201229.models.TextModerationResponse;
import lombok.SneakyThrows;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.stereotype.Service;
import java.nio.charset.StandardCharsets;
import java.time.*;
import java.util.*;


@Service
public class CommentServiceImpl implements CommentService {

	@Autowired
	private MongoTemplate mongoTemplate;

	@Autowired
	private RedissonClient redissonClient;

	@Autowired
	private KafkaTemplate<String, String> kafkaTemplate;

	@Autowired
	private AlbumClientFeign albumClientFeign;

	@Autowired
	private UserClientFeign userClientFeign;

	/***
	 * 1.实现评论提交的接口
	 *      校验:
	 *          登录访问
	 *          用户评论声音必须要购买过(1.专辑 2.声音)
	 *          一个用户一天只能对一个声音评论一次)
	 *          评论的内容不能为空,至少10个字,至多100个字
	 *          TODO-评论的内容进行审核: 色情 恐怖 政治 广告
	 *          .....自定义
	 *  a.接受前端提交的评论数据
	 *  b.校验
	 *  c.数据写入MongoDb(同步记录流水)
	 *  d.发送kafka的实时流数据(异步-完成kafka统计和下游数据入库DB,进入专辑或声音的统计表)
	 *  2.实现评论的分页条件查询(排序-时间降序)
	 *      条件: 声音id
	 *  3.拓展分页查询:
	 *        3.1: 提交评论增加一个星级字段: 1-5颗星-----好评 中评 差评
	 *        3.2: 查询的时候可以指定星级查询----好评 中评 差评
	 *
	 *  时间: 2个工作日
	 */
	@Override
	public void save(CommentVo commentVo) {

		if (commentVo == null){
			throw new GuiguException(201,"参数为空");
		}
		int length = commentVo.getContent().length();
		//获取评论字数，10<字数<100
		if (length <10 || length>100){
			throw new GuiguException(201,"错误，内容字数不在10-100之间");
		}

		//获取用户id
		Long userId = AuthContextHolder.getUserId();
		//获取声音id
		Long trackId = commentVo.getTrackId();
		//获取用户id
		Long albumId = commentVo.getAlbumId();
		//加锁
		RLock lock = redissonClient.getLock("Comment_" + userId + "trackId_" + trackId);
		lock.tryLock();
		//获取用户上一次的评论时间
		Comment one = mongoTemplate.findOne(Query.query(
						Criteria.where("userId").is(userId)
								.and("albumId").is(albumId)
								.and("trackId").is(trackId))
				.with(Sort.by("createTime").descending()), Comment.class);
		try{
			//判断是否为空
			if (one != null){
				Date createTime = one.getCreateTime();
				//转换为local date
				LocalDate localDate = LocalDate.ofInstant(createTime.toInstant(), ZoneId.systemDefault());
				//如果是同一天
				if (LocalDate.now().equals(localDate)){
					throw new GuiguException(201,"一天只能对一个声音评论哦！");
				}
			}
			//判断用户是否可以评论声音
			//判断专辑的收费类型0101免费 0102vip免费 0103付费
			//专辑是否免费
			//用户是否vip
			//是否有购买专辑或声音
			Map<String,Long> param = new HashMap<>();
			param.put("userId",userId);
			param.put("albumId",albumId);
			param.put("trackId",trackId);
			Boolean canComment = albumClientFeign.isCanComment(param);
			if (canComment){

				//判断评论内容是否包含违禁词
				isCommentPass(commentVo.getContent());

				//如果为true，可以评论
				//new comment对象
				Comment comment =new Comment();
				//将用户评论保存到comment对象
				BeanUtils.copyProperties(commentVo,comment);
				comment.setUserId(Long.valueOf(userId));
				UserInfo userInfo = userClientFeign.getUserInfo(userId);
				comment.setNickname(userInfo.getNickname());
				comment.setAvatarUrl(userInfo.getAvatarUrl());
				comment.setCreateTime(new Date());
				//保存进mongoDb
				mongoTemplate.save(comment);

				//统计评论信息：Kafka流式编程传输
				JSONObject jsonObject = new JSONObject();
				jsonObject.put("albumId",albumId);
				jsonObject.put("trackId",trackId);
				kafkaTemplate.send("commentTopic",jsonObject.toJSONString());

			}
		}catch (Exception e){
			throw e;
		}

	}

	/**
	 * 从MongoDB查询评论
	 * @param albumId
	 * @param trackId
	 * @param page
	 * @param limit
	 * @return
	 */
	@Override
	public IPage findCommentPage(Long albumId, Long trackId, Long page, Long limit) {

		Pageable pageable = PageRequest.of(page.intValue()-1,limit.intValue());

		List<Comment> comments = mongoTemplate.find(Query.query(
				Criteria.where("albumId").is(albumId).and("trackId").is(trackId)
		).with(pageable), Comment.class);

		//获取全部评论条数
		long count = mongoTemplate.count(Query.query(
				Criteria.where("albumId").is(albumId).and("trackId").is(trackId)), Comment.class);
		//构建一个page对象
		IPage iPage = new Page();
		iPage.setCurrent(page-1);//当前页

		long pageTotal = count % limit == 0 ? count /  limit: count /  limit + 1;
		iPage.setPages(pageTotal);//总页数
		iPage.setTotal(count);//总数据
		iPage.setSize(limit);//当前页

		iPage.setRecords(comments);

		return iPage;
	}

	/***
	 * 检查评论内容是否包含违禁词,只返回通过检验的
	 * @param text
	 * @return
	 */
	@SneakyThrows
	private Boolean  isCommentPass(String text) {
		// 实例化一个认证对象，入参需要传入腾讯云账户 SecretId 和 SecretKey，此处还需注意密钥对的保密
		// 代码泄露可能会导致 SecretId 和 SecretKey 泄露，并威胁账号下所有资源的安全性。以下代码示例仅供参考，建议采用更安全的方式来使用密钥，请参见：https://cloud.tencent.com/document/product/1278/85305
		// 密钥可前往官网控制台 https://console.cloud.tencent.com/cam/capi 进行获取
		Credential cred = new Credential("AKIDzGa4a8x0CLX2bGRi4rAZ3QesxsdFi1BA", "wjNrCPTzMbgnmcJqDQUQCoGZihYGSUM5");
		// 实例化一个http选项，可选的，没有特殊需求可以跳过
		HttpProfile httpProfile = new HttpProfile();
		httpProfile.setEndpoint("tms.tencentcloudapi.com");
		// 实例化一个client选项，可选的，没有特殊需求可以跳过
		ClientProfile clientProfile = new ClientProfile();
		clientProfile.setHttpProfile(httpProfile);
		// 实例化要请求产品的client对象,clientProfile是可选的
		TmsClient client = new TmsClient(cred, "ap-guangzhou", clientProfile);
		// 实例化一个请求对象,每个接口都会对应一个request对象
		TextModerationRequest req = new TextModerationRequest();
		// 要检测的文本内容
		// 将文本内容转换为UTF-8编码的字节数组
		byte[] utf8Bytes = text.getBytes(StandardCharsets.UTF_8);
		// 对UTF-8编码的字节数组进行Base64编码
		String base64Text = Base64.getEncoder().encodeToString(utf8Bytes);
		req.setContent(base64Text);
		// 返回的resp是一个TextModerationResponse的实例，与请求对象对应
		TextModerationResponse resp = client.TextModeration(req);
		// 输出json格式的字符串回包
		System.out.println(AbstractModel.toJsonString(resp));
		return resp.getSuggestion().equals("Pass");
	}
}
